﻿using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace WCAD
{
    public static class CmCurveMethod
    {
        /// <summary>
        /// 求两个曲线的交点,OnBothOperands=不延长、ExtendThis=延长曲线1、ExtendArgument=延长曲线2、ExtendBoth=延长两个曲线
        /// </summary>
        /// <param name="curve1">曲线1</param>
        /// <param name="curve2">曲线2</param>
        /// <param name="num">0=不延长、1=延长曲线1、2=延长曲线2、3=延长两个曲线</param>
        /// <returns></returns>
        public static List<Point3d> IntersectWith(this Curve curve1, Curve curve2, Intersect intersect = Intersect.OnBothOperands)
        {
            Point3dCollection pos = new Point3dCollection();
            curve1.IntersectWith(curve2, intersect, pos, IntPtr.Zero, IntPtr.Zero);
            List<Point3d> points = new List<Point3d>();
            foreach (Point3d item in pos)
            {
                points.Add(item);
            }
            return points;
        }

        /// <summary>
        /// 根据点切割curve
        /// </summary>
        /// <param name="curve"></param>
        /// <param name="points"></param>
        /// <returns></returns>
        public static List<Curve> GetSplitCurves(this Curve curve, List<Point3d> points)
        {
            List<Curve> curves = new List<Curve>();
            List<Point3d> tmps = new List<Point3d>();
            points.ForEach(p => tmps.Add(curve.GetClosestPointTo(p, false)));
            points = tmps.OrderBy(p => curve.GetParameterAtPoint(p)).ToList();
            Point3dCollection pos = new Point3dCollection();
            points.ForEach(p => pos.Add(curve.GetClosestPointTo(p, false)));
            DBObjectCollection dbs = curve.GetSplitCurves(pos);
            foreach (Curve item in dbs)
            {
                curves.Add(item);
            }
            return curves;
        }
        /// <summary>
        /// 根据点切割curve
        /// </summary>
        /// <param name="curve"></param>
        /// <param name="points"></param>
        /// <returns></returns>
        public static List<Curve> GetSplitCurves(this Curve curve, params Point3d[] points)
        {
            return curve.GetSplitCurves(points.ToList());
        }
        /// <summary>
        /// 两个曲线是否首尾相连
        /// </summary>
        /// <param name="curve1"></param>
        /// <param name="curve2"></param>
        /// <param name="tolerance">容差</param>
        /// <returns></returns>
        public static bool IsTwoCurveConnected(Curve curve1, Curve curve2, double tolerance)
        {
            Tolerance tol = new Tolerance(tolerance, tolerance);
            Point3d p1 = curve1.StartPoint;
            Point3d p2 = curve1.EndPoint;
            Point3d p3 = curve2.StartPoint;
            Point3d p4 = curve2.EndPoint;
            if (p1.IsEqualTo(p3, tol) || p1.IsEqualTo(p4, tol) || p2.IsEqualTo(p3, tol) || p2.IsEqualTo(p4, tol))
            {
                return true;
            }
            return false;
        }
        /// <summary>
        /// 点到曲线的最近距离
        /// </summary>
        /// <param name="curve"></param>
        /// <param name="point"></param>
        /// <returns></returns>
        public static double GetDis(this Curve curve,Point3d point)
        {
            Point3d po = curve.GetClosestPointTo(point, false);
            return po.DistanceTo(point);
        }
        /// <summary>
        /// 炸开多线（感觉没啥用）
        /// </summary>
        /// <param name="mline"></param>
        /// <returns></returns>
        public static List<Curve> ExplodeMline(Mline mline)
        {
            DBObjectCollection dbs = new DBObjectCollection();
            mline.Explode(dbs);
            List<Curve> curves = new List<Curve>();
            foreach (Curve item in dbs)
            {
                curves.Add(item);
            }
            return curves;
        }
        /// <summary>
        /// 找最近的一个曲线
        /// </summary>
        /// <param name="curves">曲线们</param>
        /// <param name="point">基点</param>
        /// <param name="vector">在这个方向的最近曲线</param>
        /// <returns></returns>
        public static Curve GetClosestCurve(List<Curve> curves, Point3d point, Vector3d vector)
        {
            Curve curve = null;
            Ray ray = new Ray();
            ray.BasePoint = point;
            ray.UnitDir = vector;
            double dis = double.MaxValue;
            foreach (Curve item in curves)
            {
                Point3dCollection pos = new Point3dCollection();
                item.IntersectWith(ray, Intersect.OnBothOperands, pos, IntPtr.Zero, IntPtr.Zero);
                if (pos.Count == 0) continue;
                Point3d po = pos[0];
                double tmp = po.DistanceTo(point);
                if (tmp < dis)
                {
                    dis = tmp;
                    curve = item;
                }
            }
            return curve;
        }
        /// <summary>
        /// 偏移
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ent">偏移图形</param>
        /// <param name="dis">偏移量</param>
        /// <returns></returns>
        public static T Offset<T>(this T ent, double dis) where T : Curve
        {
            return ent.GetOffsetCurves(dis)[0] as T;
        }
        /// <summary>
        /// 把曲线偏移两边，形成封闭多段线
        /// </summary>
        /// <param name="cur">曲线</param>
        /// <param name="dis">距离</param>
        /// <returns></returns>
        public static Polyline OffsetPl(this Curve cur, double dis)
        {
            Curve cur1= cur.GetOffsetCurves(dis)[0] as Curve;
            Curve cur2= cur.GetOffsetCurves(-dis)[0] as Curve;
            Line line1 = new Line(cur1.StartPoint, cur2.StartPoint);
            Line line2 = new Line(cur1.EndPoint, cur2.EndPoint);
            Polyline polyline = new Polyline();
            polyline.AddVertexAt(0, cur1.StartPoint.ToPoint2d(), 0, 0, 0);
            polyline.JoinEntity(cur1);
            polyline.JoinEntity(line1);
            polyline.JoinEntity(cur2);
            polyline.JoinEntity(line2);
            return polyline;
        }
    }
}
